﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;

namespace Server
{
    /// <summary>
    /// 基础管道
    /// </summary>
    public abstract class BasicPipe : IPipeSender
    {
        /// <summary>
        /// // 缓冲区大小 512kb
        /// </summary>
        public readonly static int maxLen = 1024 * 512;
        /// <summary>
        /// 管道名称
        /// </summary>
        protected string szPipeName;
        /// <summary>
        /// 收到数据
        /// </summary>
        public event EventHandler<PipeEventArgs> ReadDataEvent;
        /// <summary>
        /// 管道断开
        /// </summary>
        public event EventHandler<EventArgs> PipeClosedEvent;
        /// <summary>
        /// 管道
        /// </summary>
        private PipeStream m_pPipeStream;
        /// <summary>
        /// 设置管道
        /// </summary>
        /// <param name="p"></param>
        protected void SetPipeStream(PipeStream p)
        {
            m_pPipeStream = p;
        }
        /// <summary>
        /// 管道id
        /// </summary>
        /// <returns></returns>
        public abstract int PipeId();
        /// <summary>
        /// 关闭释放资源
        /// </summary>
        public void Close()
        {
            if (m_pPipeStream == null)
            {
                return;
            }
            if (!m_pPipeStream.IsConnected)
            {
                return;
            }
            m_pPipeStream.WaitForPipeDrain();
            m_pPipeStream.Close();
            m_pPipeStream.Dispose();
            m_pPipeStream = null;
        }
        /// <summary>
        /// 异步读取
        /// </summary>
        public void StartReadingAsync()
        {
            var ms = new MemoryStream();
            var t = new Thread((o) =>
            {
                bool isContinuous = false;
                while (true)
                {
                    byte[] buffer = new byte[maxLen];
                    var length = m_pPipeStream.Read(buffer, 0, maxLen);
                    if (length == 0)
                    {
                        //表示通道关闭,结束线程
                        this.PipeClosedEvent?.Invoke(this, EventArgs.Empty);
                        return;
                    }
                    if (length == maxLen)
                    {
                        isContinuous = true;
                        ms.Write(buffer, 0, length);
                        continue;
                    }
                    //表示一次就读取完成
                    if (!isContinuous)
                    {
                        this.ReadDataEvent?.Invoke(this, new PipeEventArgs(buffer, length));
                        //Console.WriteLine("一次读取完成");
                        continue;
                    }
                    ms.Write(buffer, 0, length);
                    //Console.WriteLine($"第{index}个{length}|{maxLen}|{ ms.Length}");
                    this.ReadDataEvent?.Invoke(this, new PipeEventArgs(ms.ToArray(), length));
                    ms.Dispose();
                    ms = new MemoryStream();
                    isContinuous = false;
                }
            });
            t.IsBackground = true;
            t.Start();
        }
        /// <summary>
        /// 写入字节
        /// </summary>
        /// <param name="pBytes"></param>
        protected void WriteByteArray(byte[] pBytes)
        {
            if (m_pPipeStream == null)
            {
                return;
            }
            // this will start writing, but does it copy the memory before returning?
            m_pPipeStream.Write(pBytes, 0, pBytes.Length);
        }
        /// <summary>
        /// 发送字节
        /// </summary>
        /// <param name="bytes"></param>
        public void SendBytes(byte[] bytes)
        {
            WriteByteArray(bytes);
        }
    }
    /// <summary>
    /// 收到数据
    /// </summary>
    public class PipeEventArgs : EventArgs
    {
        /// <summary>
        /// 接收到的字节
        /// </summary>
        public byte[] Bytes { get; set; }
        /// <summary>
        /// 长度
        /// </summary>
        public int Length { get; set; }
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="length"></param>
        public PipeEventArgs(byte[] bytes, int length)
        {
            Bytes = bytes;
            Length = length;
        }
    }
    /// <summary>
    /// 管道发送
    /// </summary>
    public interface IPipeSender
    {
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="bytes"></param>
        void SendBytes(byte[] bytes);
    }
    /// <summary>
    /// 服务管道
    /// </summary>
    public class ServerPipe : BasicPipe
    {
        /// <summary>
        /// 收到连接
        /// </summary>
        public event EventHandler<EventArgs> ConnectionEvent;

        NamedPipeServerStream m_pPipe;
        int m_nPipeId;

        public ServerPipe(string szPipeName, int nPipeId)
            : base()
        {
            this.szPipeName = szPipeName;
            m_nPipeId = nPipeId;
            StartService();
            this.PipeClosedEvent += ServerPipe_PipeClosedEvent;
        }
        /// <summary>
        /// 启动服务
        /// </summary>
        private void StartService()
        {
            m_pPipe = new NamedPipeServerStream(
                  szPipeName,
                  PipeDirection.InOut,
                  NamedPipeServerStream.MaxAllowedServerInstances,
                  PipeTransmissionMode.Message,
                  PipeOptions.Asynchronous);
            base.SetPipeStream(m_pPipe);
            m_pPipe.BeginWaitForConnection(new AsyncCallback(StaticGotPipeConnection), this);
        }
        /// <summary>
        /// 端口连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ServerPipe_PipeClosedEvent(object sender, EventArgs e)
        {
            //关闭
            this.Close();
            //重新创建服务
            StartService();
        }
        /// <summary>
        /// 等待连接
        /// </summary>
        /// <param name="pAsyncResult"></param>
        void StaticGotPipeConnection(IAsyncResult pAsyncResult)
        {
            ServerPipe pThis = pAsyncResult.AsyncState as ServerPipe;
            pThis.GotPipeConnection(pAsyncResult);
        }
        /// <summary>
        /// 收到连接
        /// </summary>
        /// <param name="pAsyncResult"></param>
        void GotPipeConnection(IAsyncResult pAsyncResult)
        {
            //结束等待连接
            m_pPipe.EndWaitForConnection(pAsyncResult);
            //读取数据
            StartReadingAsync();
            //连接成功
            this.ConnectionEvent?.Invoke(this, new EventArgs());
        }
        /// <summary>
        /// 管道ID
        /// </summary>
        /// <returns></returns>
        public override int PipeId() { return m_nPipeId; }
    }
}
